﻿using System;
using System.Collections.Generic;

namespace ChengNet.StrongCaml.ValueType.Abstract
{
    /// <summary>An extra namespace depth to hide a collection of "abstract" interfaces not intended for "public" implementation.</summary>
    internal class NamespaceDoc { }

    /// <summary>"Abstract" interface used only to classify valid ValueType/C# type pairings. Not intended for implementation by a concrete class.</summary>
    public interface ValueType { }
    /// <summary>"Abstract" interface. Not intended for implementation by a concrete class.</summary>
    /// <remarks>Inherited by interfaces that are used to classify SharePoint CAML field types that are represented in code by C# <c>int</c>.</remarks>
    public interface ValueInt : ValueType { }
    /// <summary>"Abstract" interface. Not intended for implementation by a concrete class.</summary>
    /// <remarks>Inherited by interfaces that are used to classify SharePoint CAML field types that are represented in code by C# <c>string</c>.</remarks>
    public interface ValueString : ValueType { }
    /// <summary>"Abstract" interface. Not intended for implementation by a concrete class.</summary>
    /// <remarks>Inherited by interfaces that are used to classify SharePoint CAML field types that are represented in code by C# User.</remarks>
    public interface ValueUser : ValueType { }
}

namespace ChengNet.StrongCaml.ValueType
{
    /// <summary>
    /// <para>Interfaces used as C++ templates in <see cref="M:Caml.Value{T}"/> methods. Analogue to the CAML Type attribute in &lt;Value&gt; tags.</para>
    /// <para>a C# string can be a Caml Text or Caml Note</para>
    /// <para>a C# integer can be a Caml Integer, a Caml Lookup, or a Caml User</para>
    /// <para>a C# User can also be a Caml Integer, a Caml Lookup, or a Caml User</para>
    /// </summary>
    internal class NamespaceDoc { }

    /// <summary>SharePoint Boolean type</summary>
    public interface Boolean : Abstract.ValueType { }
    /// <summary>SharePoint Integer type</summary>
    public interface Integer : Abstract.ValueInt, Abstract.ValueUser { }
    /// <summary>SharePoint Lookup type for lookup fields</summary>
    public interface Lookup : Abstract.ValueInt, Abstract.ValueUser { }
    /// <summary>SharePoint single-line Text type</summary>
    public interface Text : Abstract.ValueString { }
    /// <summary>SharePoint multi-line Note type</summary>
    public interface Note : Abstract.ValueString { }
    /// <summary>SharePoint DateTime type</summary>
    public interface DateTime : Abstract.ValueType { }
    /// <summary>SharePoint User type</summary>
    public interface User : Abstract.ValueInt, Abstract.ValueUser { }
}

namespace ChengNet.StrongCaml.Node
{
    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Value<T> : CamlNode
        where T : ValueType.Abstract.ValueType
    {
        internal CamlNode Child { get { return (Children != null && Children.Count > 0) ? Children[0] : null; } }

        private void Init(string type) {
            Attributes = new Dictionary<string, string>() { { "Type", type } };
        }

        internal Value(bool value) : base(value) { }

        internal Value(int value)
            : base(value) {
            var typeName = typeof(T).Name;
            if (typeName == "ValueInt") typeName = "Integer";
            Init(typeName);
        }

        internal Value(string str)
            : base(str) {
            var typeName = typeof(T).Name;
            if (typeName == "ValueString") typeName = "Text";
            Init(typeName);
        }

        internal Value(DateTime dateTime, TimeValue timeValue = TimeValue.Exclude)
            : base(dateTime) {
            Init(typeof(T).Name);
            if (timeValue == TimeValue.Include) Attributes["IncludeTimeValue"] = true.ToString().ToUpper();
        }

        internal Value(Now now, TimeValue timeValue = TimeValue.Exclude)
            : base(now) {
            Init(typeof(T).Name);
            if (timeValue == TimeValue.Include) Attributes["IncludeTimeValue"] = true.ToString().ToUpper();
        }

        internal Value(Today today) : base(today) { Init(typeof(T).Name); }

        internal Value(UserID userID)
            : base(userID) {
            Init(typeof(T).Name);
        }
    }
}
